<?php

class Paging
{
    private $_pages_to_display;
    private $_records_per_page;
    private $_total_records;
    private $_dispatched;
    private $_total_pages;
    private $_current_page;
    private $_low_offset;
    private $_high_offset;
    private $_show_first;
    private $_show_last;
    private $_data;

    /**
     * @param $total_records int|array tổng số mẫu tin
     * @param int $current_page trang hiện tại
     * @param int $records_per_page số mẫu tin ở mỗi trang
     * @param int $pages_to_display số trang 1 lần hiển thị
     */
    public function __construct($total_records, $current_page = 1, $records_per_page = 10, $pages_to_display = 10)
    {
        if (is_array($total_records)) {
            $this->_total_records = count($total_records);
            $this->_data =& $total_records;
        }
        $this->_records_per_page = $records_per_page;
        $this->_pages_to_display = $pages_to_display;
        $this->_current_page = $current_page;

        # Chưa xử lý
        $this->_dispatched = false;
    }

    public function dispatch()
    {
        # Tổng số trang
        $this->_total_pages = round(ceil($this->_total_records / $this->_records_per_page));

        if ($this->_current_page > $this->_total_pages) {
            $this->_current_page %= $this->_total_pages;
        }

        # Trường hợp số trang tính được ít hơn số trang 1 lần hiển thị
        if ($this->_total_pages <= $this->_pages_to_display) {
            $this->_low_offset = 1;
            $this->_high_offset = $this->_total_pages;
            $this->_show_first = false;
            $this->_show_last = false;
        } else {
            $middle_offset = ceil($this->_pages_to_display / 2);

            $low = $this->_current_page - $middle_offset + 1;
            $high = $this->_current_page + $middle_offset;
            if ($low <= 1) {
                $this->_low_offset = 1;
                $this->_high_offset = $this->_pages_to_display - 1;
                $this->_show_last = true;
                $this->_show_first = false;
            } elseif ($high > $this->_total_pages) {
                $this->_high_offset = $this->_total_pages;
                $this->_low_offset = $this->_total_pages - $this->_pages_to_display + 2;
                $this->_show_first = true;
                $this->_show_last = false;
            } else {
                $this->_low_offset = $low + 1;
                $this->_high_offset = $low + $this->_pages_to_display - 2;
                $this->_show_first = true;
                $this->_show_last = true;
            }
        }
        $this->_dispatched = true;
    }

    public function __set($key, $value)
    {
        $fields = array(
            'totalRecords' => '_total_records',
            'pagesToDisplay' => '_pages_to_display',
            'recordsPerPage' => '_records_per_page',
            'currentPage' => '_current_page'
        );
        if (array_key_exists($key, $fields)) {
            $this->_dispatched = false;
            $this->{$fields[$key]} = $value;
        } else {
            throw new Exception("Paginator class: Set not found property ({$key})!");
        }
    }

    public function getData()
    {
        if (!$this->_dispatched) {
            $this->dispatch();
        }
        $data = array_slice($this->_data, $this->lowOffsetRecord, $this->highOffsetRecord - $this->lowOffsetRecord + 1);

        return $data;
    }

    public function getLowOffsetRecord()
    {
        return $this->lowOffsetRecord;
    }

    public function getHighOffsetRecord()
    {
        return $this->highOffsetRecord;
    }

    public function getLowOffsetPage()
    {
            return $this->_low_offset;
    }

    public function getHighOffsetPage()
    {
        return $this->_high_offset;
    }

    public function __get($key)
    {
        if (!$this->_dispatched) {
            $this->dispatch();
        }
        $fields = array(
            'lowOffset' => '_low_offset',
            'highOffset' => '_high_offset',
            'showFirst' => '_show_first',
            'showLast' => '_show_last',
            'totalPages' => '_total_pages',
            'currentPage' => '_current_page'
        );
        if (array_key_exists($key, $fields)) {
            return $this->{$fields[$key]};
        } elseif ($key == "lowOffsetRecord") {
            $offset = ($this->_current_page - 1) * $this->_records_per_page;
            if ($offset < 0) {
                return 0;
            } else {
                return $offset;
            }
        } elseif ($key == "highOffsetRecord") {
            $offset = ($this->_current_page * $this->_records_per_page - 1);
            if ($offset >= $this->_total_records) {
                return $this->_total_records - 1;
            } else {
                return $offset;
            }
        }
        else {
            throw new Exception("Paginator class: get not found property ({$key})!");
        }
    }

    public function pagesList($baseHref)
    {
        $list = array();
        if ($this->_show_first) {
            $list[] = $this->addPage($baseHref . '1', 'Trang đầu');
        }
        for ($i = $this->_low_offset; $i <= $this->_high_offset; $i++) {
            $list[] = $this->addPage($baseHref . $i, $i, $i == $this->_current_page);
        }
        if ($this->_show_last) {
            $list[] = $this->addPage($baseHref . $this->_total_pages, 'Trang cuối');
        }
        return $list;

    }

    private function addPage($href, $title, $current = false)
    {
        $page = compact('href', 'title', 'current');
        return $page;
    }
}